<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  <title>MBean与JMX | Eetal&#39;s Blog</title>

  <!-- keywords -->
  

  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta name="description" content="欢迎查看Eetal的第二十二篇博客–MBean与JMX JMXJMX(java Management Exetensions)在Java编程语言中定义了应用程序以及网络管理和监控的体系结构、设计模式、应用程序接口以及服务。通常使用JMX来监控系统的运行状态或管理系统的某些方面，比如清空缓存、重新加载配置文件等优点是可以非常容易的使应用程序被管理伸缩性的架构使每个JMX Agent Service可">
<meta property="og:type" content="article">
<meta property="og:title" content="MBean与JMX">
<meta property="og:url" content="http://eetal.gitee.io/blog/2019/07/08/MBean与JMX/index.html">
<meta property="og:site_name" content="Eetal&#39;s Blog">
<meta property="og:description" content="欢迎查看Eetal的第二十二篇博客–MBean与JMX JMXJMX(java Management Exetensions)在Java编程语言中定义了应用程序以及网络管理和监控的体系结构、设计模式、应用程序接口以及服务。通常使用JMX来监控系统的运行状态或管理系统的某些方面，比如清空缓存、重新加载配置文件等优点是可以非常容易的使应用程序被管理伸缩性的架构使每个JMX Agent Service可">
<meta property="og:locale" content="default">
<meta property="og:image" content="http://eetal.gitee.io/blog/images/mbean/jconsole.jpg">
<meta property="og:image" content="http://eetal.gitee.io/blog/images/mbean/mbean.jpg">
<meta property="og:image" content="http://eetal.gitee.io/blog/images/mbean/mbean属性.jpg">
<meta property="og:updated_time" content="2019-07-31T18:18:03.432Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="MBean与JMX">
<meta name="twitter:description" content="欢迎查看Eetal的第二十二篇博客–MBean与JMX JMXJMX(java Management Exetensions)在Java编程语言中定义了应用程序以及网络管理和监控的体系结构、设计模式、应用程序接口以及服务。通常使用JMX来监控系统的运行状态或管理系统的某些方面，比如清空缓存、重新加载配置文件等优点是可以非常容易的使应用程序被管理伸缩性的架构使每个JMX Agent Service可">
<meta name="twitter:image" content="http://eetal.gitee.io/blog/images/mbean/jconsole.jpg">
  
    <link rel="alternative" href="/atom.xml" title="Eetal&#39;s Blog" type="application/atom+xml">
  
  
    <link rel="icon" href="http://www.yangyitao.top/FiveChess/resource/ico/favicon.ico">
  
  <link rel="stylesheet" href="/blog/css/style.css">
  
  

  <script src="//cdn.bootcss.com/require.js/2.3.2/require.min.js"></script>
  <script src="//cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>

  
</head>
<body>
  <div id="container">
    <div id="particles-js"></div>
    <div class="left-col">
    <div class="overlay"></div>
<div class="intrude-less">
	<header id="header" class="inner">
		<a href="/" class="profilepic">
			
			<img lazy-src="/blog/images/head.jpg" class="js-avatar">
			
		</a>

		<hgroup>
		  <h1 class="header-author"><a href="/">Eetal</a></h1>
		</hgroup>

		
		<p class="header-subtitle">java coder</p>
		

		
			<div class="switch-btn">
				<div class="icon">
					<div class="icon-ctn">
						<div class="icon-wrap icon-house" data-idx="0">
							<div class="birdhouse"></div>
							<div class="birdhouse_holes"></div>
						</div>
						<div class="icon-wrap icon-ribbon hide" data-idx="1">
							<div class="ribbon"></div>
						</div>
						
						<div class="icon-wrap icon-link hide" data-idx="2">
							<div class="loopback_l"></div>
							<div class="loopback_r"></div>
						</div>
						
						
					</div>
					
				</div>
				<div class="tips-box hide">
					<div class="tips-arrow"></div>
					<ul class="tips-inner">
						<li>菜单</li>
						<li>标签</li>
						
						<li>友情链接</li>
						
						
					</ul>
				</div>
			</div>
		

		<div class="switch-area">
			<div class="switch-wrap">
				<section class="switch-part switch-part1">
					<nav class="header-menu">
						<ul>
						
							<li><a href="/blog/">Home</a></li>
				        
							<li><a href="/blog/archives">Archives</a></li>
				        
						</ul>
					</nav>
					<nav class="header-nav">
						<div class="social">
							
						</div>
					</nav>
				</section>
				
				
				<section class="switch-part switch-part2">
					<div class="widget tagcloud" id="js-tagcloud">
						
					</div>
				</section>
				
				
				
				<section class="switch-part switch-part3">
					<div id="js-friends">
					
			          <a target="_blank" class="main-nav-link switch-friends-link" href="https://github.com/smackgg/hexo-theme-smackdown">smackdown</a>
			        
			        </div>
				</section>
				

				
			</div>
		</div>
	</header>				
</div>
    </div>
    <div class="mid-col">
      <nav id="mobile-nav">
  	<div class="overlay">
  		<div class="slider-trigger"></div>
  		<h1 class="header-author js-mobile-header hide">Eetal</h1>
  	</div>
	<div class="intrude-less">
		<header id="header" class="inner">
			<div class="profilepic">
				<img lazy-src="/blog/images/head.jpg" class="js-avatar">
			</div>
			<hgroup>
			  <h1 class="header-author">Eetal</h1>
			</hgroup>
			
			<p class="header-subtitle">java coder</p>
			
			<nav class="header-menu">
				<ul>
				
					<li><a href="/blog/">Home</a></li>
		        
					<li><a href="/blog/archives">Archives</a></li>
		        
		        <div class="clearfix"></div>
				</ul>
			</nav>
			<nav class="header-nav">
				<div class="social">
					
				</div>
			</nav>
		</header>				
	</div>
</nav>
      <div class="body-wrap"><article id="post-MBean与JMX" class="article article-type-post" itemscope itemprop="blogPost">
  
    <div class="article-meta">
      <a href="/blog/2019/07/08/MBean与JMX/" class="article-date">
  	<time datetime="2019-07-08T15:17:12.569Z" itemprop="datePublished">2019-07-08</time>
</a>
    </div>
  
  <div class="article-inner">
    
      <input type="hidden" class="isFancy" />
    
    
      <header class="article-header">
        
  
    <h1 class="article-title" itemprop="name">
      MBean与JMX
      
    </h1>
  

      </header>
      
      <div class="article-info article-info-post">
        
        

        
        <div class="clearfix"></div>
      </div>
      
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>欢迎查看Eetal的第二十二篇博客–MBean与JMX</p>
<h2 id="JMX"><a href="#JMX" class="headerlink" title="JMX"></a>JMX</h2><p>JMX(java Management Exetensions)在Java编程语言中定义了应用程序以及网络管理和监控的体系结构、设计模式、应用程序接口以及服务。<br>通常使用JMX来监控系统的运行状态或管理系统的某些方面，比如清空缓存、重新加载配置文件等<br>优点是可以非常容易的使应用程序被管理<br>伸缩性的架构使每个JMX Agent Service可以很容易的放入到Agent中，每个JMX的实现都提供几个核心的Agent Service，你也可以自己编写服务，服务可以很容易的部署，取消部署。<br>主要作用是提供接口，允许有不同的实现<br>简单来说，jmx是一个用来管理javaBean并可以进行监控的扩展规范，结合MBeanServer、rmi与http等可以作为一个服务监控和提供中心</p>
<h2 id="MBeanServer"><a href="#MBeanServer" class="headerlink" title="MBeanServer"></a>MBeanServer</h2><p>MBeanServer是JMX代理的核心组件。<br>它是在代理中向管理操作公开的对象的注册表。<br>向MBeanServer注册的任何对象都对管理应用程序可见。<br>MBeanServer仅公开MBean的管理接口，而不是它的直接对象引用。<br>您要从代理的Java VM外部管理的任何资源都必须在MBeanServer中注册为MBean。<br>MBeanServer还提供标准化接口，用于访问同一Java VM中的MBean，为本地对象提供操作可管理资源的所有好处。<br>需要注意的是，一般不使用MBeanServerFactory.createMBeanServer()，使用ManagementFactory.getPlatformMBeanServer()<br>后者在当前尚未在ManagementFactory中注册静态成员MBeanServer时，会先使用MBeanServerFactory.createMBeanServer()创建一个MBeanServer并将其注册到静态成员，后续每次调用会直接返回该成员实例<br>并且ManagementFactory.getPlatformMBeanServer()方法在第一次调用createMBeanServer()实例化MBeanServer以后，会读取PlatformComponent枚举的枚举值，将一些系统必要的MBean注册到MBeanServer<br>JConsole监控的MBeanServer就是在ManagementFactory中注册的静态成员MBeanServe<br>所以如果没有特殊配置的MBeanServer，jconsole是不会监控的</p>
<h2 id="Agent"><a href="#Agent" class="headerlink" title="Agent"></a>Agent</h2><p>Java Management Extensions（JMX）Agent是一个在Java虚拟机（Java VM）中运行的管理实体.<br>充当MBean和管理应用程序(JConsole等)之间的联络人<br>Agent只是一个规范，一般会封装我们创建和启动MBeanServer以及注册MBean的过程在一个Agent行为里，方便启动</p>
<h2 id="Agent-Service"><a href="#Agent-Service" class="headerlink" title="Agent Service"></a>Agent Service</h2><p>Agent Service是可以对MBeanServer中注册的MBean执行管理操作的对象。<br>通过将管理智能包含在代理中，JMX可帮助您构建更强大的管理解决方案。<br>Agent Service通常也是MBean，允许通过MBeanServer控制它们及其功能。<br>JMX规范定义了以下Agent Service：<br>通过管理applet（m-let）服务的动态类加载检索并实例化从网络动态下载的新类和本机库。<br>监视器观察MBean属性的数字或字符串值，并可以向其他对象通知几种类型的更改。<br>定时器提供调度机制，并且可以以预定间隔发送通知。<br>关系服务定义MBean之间的关联并维护关系的一致性。</p>
<h2 id="Protocol-Adaptors-and-Connectors"><a href="#Protocol-Adaptors-and-Connectors" class="headerlink" title="Protocol Adaptors and Connectors"></a>Protocol Adaptors and Connectors</h2><p>Protocol adaptors and connectors使代理可从远程(通过rmi或者http等协议)管理应用程序访问。<br>它们通过在MBean服务器中实例化和注册的MBean的特定协议提供视图。<br>它们使Java VM外部的管理应用程序能够：<br>获取或设置现有MBean的属性<br>对现有MBean执行操作<br>实例化并注册新的MBean<br>注册并接收MBean发出的通知<br>因此，要使JMX代理易于管理，它必须至少包含一个协议适配器或连接器。<br>Java SE平台包括标准RMI连接器。Agent可以包括任意数量的协议适配器和连接器，允许通过不同的协议同时远程管理和监视它</p>
<h3 id="Protocol-Adaptors"><a href="#Protocol-Adaptors" class="headerlink" title="Protocol Adaptors"></a>Protocol Adaptors</h3><p>Protocol Adaptors通过给定协议提供JMX代理的管理视图。<br>它们将MBean和MBean服务器的操作调整为给定协议中的表示，<br>并可能调整为不同的信息模型，例如SNMP。Java SE平台不包括任何协议适配器作为标准。<br>连接到Protocol Adaptors的管理应用程序通常特定于给定的协议。<br>这通常是依赖于特定管理协议的传统管理解决方案的情况。<br>它们不是通过MBean服务器的远程表示来访问JMX代理，而是通过映射到MBeanServer的操作来访问JMX代理。</p>
<h3 id="Connectors"><a href="#Connectors" class="headerlink" title="Connectors"></a>Connectors</h3><p>Connectors用于将代理与为JMX技术启用的远程管理应用程序连接，即使用JMX规范的分布式服务开发的管理应用程序。<br>这种通信涉及Agent中的连接器服务器和管理器中的连接器客户端。<br>这些组件以特定协议的方式透明地传递管理操作。<br>JMX Remote API为MBeanServer提供远程接口，管理应用程序可以通过该接口执行操作。<br>Connectors特定于给定协议，但管理应用程序可以无差别地使用任何Connectors，因为它们具有相同的远程接口。</p>
<h2 id="MBean"><a href="#MBean" class="headerlink" title="MBean"></a>MBean</h2><p>描述一个可管理的资源。是一个java对象，遵循以下一些规则：<br>1.必须是公用的，非抽象的类<br>2.必须有至少一个公用的构造器<br>3.必须实现它自己的相应的MBean接口或者实现javax.management.DynamicMBean接口<br>4.可选的，一个MBean可以实现javax.management.NotificationBroadcaster接口MBean的类型<br>MBean使用ObjectName以keyValue形式注册到MBeanServer上</p>
<h3 id="Standard-MBean"><a href="#Standard-MBean" class="headerlink" title="Standard MBean"></a>Standard MBean</h3><p>标准MBean，也是最简单的MBean，通过类实现的接口名称来识别MBean<br>接口名称以MBean结尾，实现类需要匹配接口名称的前半部分<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">public interface YytMBean&#123;</span><br><span class="line">	public void setName(String name);</span><br><span class="line">	public String getName();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">public class Yyt implements YytMBean&#123;</span><br><span class="line">	private String name;</span><br><span class="line">	@Override</span><br><span class="line">	public void setName(String name) &#123;</span><br><span class="line">		this.name = name;</span><br><span class="line">	&#125;</span><br><span class="line">	@Override</span><br><span class="line">	public String <span class="function"><span class="title">getName</span></span>() &#123;</span><br><span class="line">		<span class="built_in">return</span> name;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">public class YytAgent&#123;</span><br><span class="line">	private String domainName;</span><br><span class="line">	private int rmiPort;</span><br><span class="line">	public YytAgent(String domainName,int rmiPort) &#123;</span><br><span class="line">		this.domainName = domainName;</span><br><span class="line">		this.rmiPort = rmiPort;</span><br><span class="line">	&#125;</span><br><span class="line">	public void start() throws MalformedObjectNameException, InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException, IOException &#123;</span><br><span class="line">		//MBeanServerFactory.createMBeanServer();	//don<span class="string">'t use this</span></span><br><span class="line"><span class="string">		MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();	//use this instead</span></span><br><span class="line"><span class="string">		</span></span><br><span class="line"><span class="string">		YytMBean yytMBean = new Yyt();</span></span><br><span class="line"><span class="string">		ObjectName objectName = new ObjectName(domainName+":name=Yyt");</span></span><br><span class="line"><span class="string">		mBeanServer.registerMBean(yytMBean, objectName);</span></span><br><span class="line"><span class="string">		</span></span><br><span class="line"><span class="string">		LocateRegistry.createRegistry(rmiPort);//开启rmi端口监听，在jmxConnectorServer.start()时会根据serviceUrl建立一个rmiServer监听该rmi端口</span></span><br><span class="line"><span class="string">		</span></span><br><span class="line"><span class="string">		JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:"+rmiPort+"/"+domainName);</span></span><br><span class="line"><span class="string">        JMXConnectorServer jmxConnectorServer = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mBeanServer);</span></span><br><span class="line"><span class="string">        jmxConnectorServer.start();</span></span><br><span class="line"><span class="string">        //开启jmx协议的监控服务器，因为java自带rmi的工具和依赖，可以直接开启，通过jconsole等支持jmx协议的客户端可以监控MBeanServer	</span></span><br><span class="line"><span class="string">	&#125;</span></span><br><span class="line"><span class="string">&#125;</span></span><br></pre></td></tr></table></figure>
<h2 id="使用JConsole工具监控"><a href="#使用JConsole工具监控" class="headerlink" title="使用JConsole工具监控"></a>使用JConsole工具监控</h2><p>JConsole是java自带的监控程序，独立jre中没有，jdk下的jre具备</p>
<p>运行java应用时带上参数<br>-Dcom.sun.management.jmxremote<br>-Dcom.sun.management.jmxremote.port=8999<br>-Dcom.sun.management.jmxremote.authenticate=false<br>-Dcom.sun.management.jmxremote.ssl=false<br>关闭ssl和密码校验，开启远程监控端口8999，这时可以直接使用jconsole进行链接</p>
<p>或者在jdk\jre\lib\management目录下，复制一份jmxremote.password.template的文件，改名去掉.template后缀，并去掉文件末尾两行示例的用户名和密码注释，修改密码为自己想要的<br>运行加上参数<br>-Djava.rmi.server.hostname=应用所在服务器的ip或者域名<br>-Dcom.sun.management.jmxremote<br>-Dcom.sun.management.jmxremote.port=监控端口<br>-Dcom.sun.management.jmxremote.rmi.port=rmi监控端口（一般与监控端口保持一致）<br>-Dcom.sun.management.jmxremote.authenticate=true<br>-Dcom.sun.management.jmxremote.ssl=false<br>这时使用JConsole链接会提示需要输入用户名和密码</p>
<p>在命令行输入jconsole运行jconsole程序<br><img src="/blog/images/mbean/jconsole.jpg" alt="jconsole"><br>在jconsole的界面，因为是本地，直接选择本地进程，进入监控页面<br>点击导航栏的MBean即可看到我们注册的MBean在列表中<br><img src="/blog/images/mbean/mbean.jpg" alt="jconsole"><br>还可以对Bean的属性值进行查看和设置<br><img src="/blog/images/mbean/mbean属性.jpg" alt="jconsole"></p>
<h2 id="源码分析"><a href="#源码分析" class="headerlink" title="源码分析"></a>源码分析</h2><h3 id="ManagementFactory-getPlatformMBeanServer"><a href="#ManagementFactory-getPlatformMBeanServer" class="headerlink" title="ManagementFactory.getPlatformMBeanServer()"></a>ManagementFactory.getPlatformMBeanServer()</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line">SecurityManager sm = System.getSecurityManager();</span><br><span class="line">      <span class="keyword">if</span> (sm != null) &#123;</span><br><span class="line">          Permission perm = new MBeanServerPermission(<span class="string">"createMBeanServer"</span>);</span><br><span class="line">          sm.checkPermission(perm);</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (platformMBeanServer == null) &#123;</span><br><span class="line">          platformMBeanServer = MBeanServerFactory.createMBeanServer();</span><br><span class="line">          <span class="keyword">for</span> (PlatformComponent pc : PlatformComponent.values()) &#123;</span><br><span class="line">              List&lt;? extends PlatformManagedObject&gt; list =</span><br><span class="line">                  pc.getMXBeans(pc.getMXBeanInterface());</span><br><span class="line">              <span class="keyword">for</span> (PlatformManagedObject o : list) &#123;</span><br><span class="line">                  // Each PlatformComponent represents one management</span><br><span class="line">                  // interface. Some MXBean may extend another one.</span><br><span class="line">                  // The MXBean instances <span class="keyword">for</span> one platform component</span><br><span class="line">                  // (returned by pc.getMXBeans()) might be also</span><br><span class="line">                  // the MXBean instances <span class="keyword">for</span> another platform component.</span><br><span class="line">                  // e.g. com.sun.management.GarbageCollectorMXBean</span><br><span class="line">                  //</span><br><span class="line">                  // So need to check <span class="keyword">if</span> an MXBean instance is registered</span><br><span class="line">                  // before registering into the platform MBeanServer</span><br><span class="line">                  <span class="keyword">if</span> (!platformMBeanServer.isRegistered(o.getObjectName())) &#123;</span><br><span class="line">                      addMXBean(platformMBeanServer, o);</span><br><span class="line">                  &#125;</span><br><span class="line">              &#125;</span><br><span class="line">          &#125;</span><br><span class="line">          HashMap&lt;ObjectName, DynamicMBean&gt; dynmbeans =</span><br><span class="line">                  ManagementFactoryHelper.getPlatformDynamicMBeans();</span><br><span class="line">          <span class="keyword">for</span> (Map.Entry&lt;ObjectName, DynamicMBean&gt; e : dynmbeans.entrySet()) &#123;</span><br><span class="line">              addDynamicMBean(platformMBeanServer, e.getValue(), e.getKey());</span><br><span class="line">          &#125;</span><br><span class="line">          <span class="keyword">for</span> (final PlatformManagedObject o :</span><br><span class="line">                                     ExtendedPlatformComponent.getMXBeans()) &#123;</span><br><span class="line">              <span class="keyword">if</span> (!platformMBeanServer.isRegistered(o.getObjectName())) &#123;</span><br><span class="line">                  addMXBean(platformMBeanServer, o);</span><br><span class="line">              &#125;</span><br><span class="line">          &#125;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="built_in">return</span> platformMBeanServer;</span><br></pre></td></tr></table></figure>
<p>ManagementFactory中定义一个platformMBeanServer成员来装载创建好的MBeanServer<br>在执行该方法的第一步会先校验当前安全权限<br>在platformMBeanServer尚未绑定一个实例时，会先使用MBeanServerFactory.createMBeanServer()实例一个MBeanServer对象<br>接下来主要是读取PlatformComponent.values()以及别的枚举类和helper类的值和成员，将系统预设的MBean注册到MBeanServer<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line">enum PlatformComponent &#123;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * Class loading system of the Java virtual machine.</span><br><span class="line">     */</span><br><span class="line">    CLASS_LOADING(</span><br><span class="line">        <span class="string">"java.lang.management.ClassLoadingMXBean"</span>,</span><br><span class="line">        <span class="string">"java.lang"</span>, <span class="string">"ClassLoading"</span>, defaultKeyProperties(),</span><br><span class="line">        <span class="literal">true</span>, // singleton</span><br><span class="line">        new MXBeanFetcher&lt;ClassLoadingMXBean&gt;() &#123;</span><br><span class="line">            public List&lt;ClassLoadingMXBean&gt; <span class="function"><span class="title">getMXBeans</span></span>() &#123;</span><br><span class="line">                <span class="built_in">return</span> Collections.singletonList(ManagementFactoryHelper.getClassLoadingMXBean());</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;),</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * Compilation system of the Java virtual machine.</span><br><span class="line">     */</span><br><span class="line">    COMPILATION(</span><br><span class="line">        <span class="string">"java.lang.management.CompilationMXBean"</span>,</span><br><span class="line">        <span class="string">"java.lang"</span>, <span class="string">"Compilation"</span>, defaultKeyProperties(),</span><br><span class="line">        <span class="literal">true</span>, // singleton</span><br><span class="line">        new MXBeanFetcher&lt;CompilationMXBean&gt;() &#123;</span><br><span class="line">            public List&lt;CompilationMXBean&gt; <span class="function"><span class="title">getMXBeans</span></span>() &#123;</span><br><span class="line">                CompilationMXBean m = ManagementFactoryHelper.getCompilationMXBean();</span><br><span class="line">                <span class="keyword">if</span> (m == null) &#123;</span><br><span class="line">                   <span class="built_in">return</span> Collections.emptyList();</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                   <span class="built_in">return</span> Collections.singletonList(m);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;),</span><br><span class="line">	.....</span><br><span class="line">	&#125;</span><br></pre></td></tr></table></figure></p>
<h3 id="MBeanServerFactory-createMBeanServer"><a href="#MBeanServerFactory-createMBeanServer" class="headerlink" title="MBeanServerFactory.createMBeanServer()"></a>MBeanServerFactory.createMBeanServer()</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line">   public static MBeanServer <span class="function"><span class="title">createMBeanServer</span></span>() &#123;</span><br><span class="line">       <span class="built_in">return</span> createMBeanServer(null);</span><br><span class="line">   &#125;</span><br><span class="line"> public static MBeanServer createMBeanServer(String domain)  &#123;</span><br><span class="line">	checkPermission(<span class="string">"createMBeanServer"</span>);</span><br><span class="line"></span><br><span class="line">	final MBeanServer mBeanServer = newMBeanServer(domain);</span><br><span class="line">	addMBeanServer(mBeanServer);</span><br><span class="line">	<span class="built_in">return</span> mBeanServer;</span><br><span class="line">&#125;</span><br><span class="line">public static MBeanServer newMBeanServer(String domain)  &#123;</span><br><span class="line">       checkPermission(<span class="string">"newMBeanServer"</span>);</span><br><span class="line"></span><br><span class="line">       // Get the builder. Creates a new one <span class="keyword">if</span> necessary.</span><br><span class="line">       //</span><br><span class="line">       final MBeanServerBuilder mbsBuilder = getNewMBeanServerBuilder();</span><br><span class="line">       // Returned value cannot be null.  NullPointerException <span class="keyword">if</span> violated.</span><br><span class="line"></span><br><span class="line">       synchronized(mbsBuilder) &#123;</span><br><span class="line">           final MBeanServerDelegate delegate  =</span><br><span class="line">                   mbsBuilder.newMBeanServerDelegate();</span><br><span class="line">           <span class="keyword">if</span> (delegate == null) &#123;</span><br><span class="line">               final String msg =</span><br><span class="line">                       <span class="string">"MBeanServerBuilder.newMBeanServerDelegate() "</span> +</span><br><span class="line">                       <span class="string">"returned null"</span>;</span><br><span class="line">               throw new JMRuntimeException(msg);</span><br><span class="line">           &#125;</span><br><span class="line">           final MBeanServer mbeanServer =</span><br><span class="line">                   mbsBuilder.newMBeanServer(domain,null,delegate);</span><br><span class="line">           <span class="keyword">if</span> (mbeanServer == null) &#123;</span><br><span class="line">               final String msg =</span><br><span class="line">                       <span class="string">"MBeanServerBuilder.newMBeanServer() returned null"</span>;</span><br><span class="line">               throw new JMRuntimeException(msg);</span><br><span class="line">           &#125;</span><br><span class="line">           <span class="built_in">return</span> mbeanServer;</span><br><span class="line">       &#125;</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure>
<p>createMBeanServer方法会调用newMBeanServer方法实例化MBeanServer<br>newMBeanServer方法中会先使用MBeanServerBuilder.newMBeanServerDelegate()实例化一个MBeanServerBuilder<br>再使用MBeanServerBuilder.newMBeanServer(domain,null,delegate)方法实例化一个MBeanServer<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">public MBeanServer newMBeanServer(String  defaultDomain,</span><br><span class="line">                                    MBeanServer  outer,</span><br><span class="line">                                    MBeanServerDelegate delegate) &#123;</span><br><span class="line">      // By default, MBeanServerInterceptors are disabled.</span><br><span class="line">      // Use com.sun.jmx.mbeanserver.MBeanServerBuilder to obtain</span><br><span class="line">      // MBeanServers on <span class="built_in">which</span> MBeanServerInterceptors are enabled.</span><br><span class="line">      <span class="built_in">return</span> JmxMBeanServer.newMBeanServer(defaultDomain,outer,delegate,</span><br><span class="line">                                           <span class="literal">false</span>);</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure></p>
<p>newMBeanServer方法实际实例化并返回的是一个JmxMBeanServer对象<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line">//<span class="keyword">in</span> JmxMBeanServer</span><br><span class="line">   public static MBeanServer newMBeanServer(String defaultDomain,</span><br><span class="line">                                            MBeanServer outer,</span><br><span class="line">                                            MBeanServerDelegate delegate,</span><br><span class="line">                                            boolean interceptors) &#123;</span><br><span class="line">       // Determine whether to use fair locking <span class="keyword">for</span> the repository.</span><br><span class="line">       // Default is <span class="literal">true</span>.</span><br><span class="line">       final boolean fairLock = DEFAULT_FAIR_LOCK_POLICY;</span><br><span class="line"></span><br><span class="line">       checkNewMBeanServerPermission();</span><br><span class="line"></span><br><span class="line">       // This constructor happens to disregard the value of the interceptors</span><br><span class="line">       // flag - that is, it always uses the default value - <span class="literal">false</span>.</span><br><span class="line">       // This is admitedly a bug, but we chose not to fix it <span class="keyword">for</span> now</span><br><span class="line">       // since we would rather not have anybody depending on the Sun private</span><br><span class="line">       // interceptor APIs - <span class="built_in">which</span> is most probably going to be removed and</span><br><span class="line">       // replaced by a public (javax) feature <span class="keyword">in</span> the future.</span><br><span class="line">       //</span><br><span class="line">       <span class="built_in">return</span> new JmxMBeanServer(defaultDomain,outer,delegate,null,</span><br><span class="line">                                 interceptors,fairLock);</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">JmxMBeanServer(String domain, MBeanServer outer,</span><br><span class="line">                  MBeanServerDelegate    delegate,</span><br><span class="line">                  MBeanInstantiator      instantiator,</span><br><span class="line">                  boolean                interceptors,</span><br><span class="line">                  boolean                fairLock)  &#123;</span><br><span class="line"></span><br><span class="line">       <span class="keyword">if</span> (instantiator == null) &#123;</span><br><span class="line">           final ModifiableClassLoaderRepository</span><br><span class="line">               clr = new ClassLoaderRepositorySupport();</span><br><span class="line">           instantiator = new MBeanInstantiator(clr);</span><br><span class="line">       &#125;</span><br><span class="line"></span><br><span class="line">       final MBeanInstantiator fInstantiator = instantiator;</span><br><span class="line">       this.secureClr = new</span><br><span class="line">           SecureClassLoaderRepository(AccessController.doPrivileged(new PrivilegedAction&lt;ClassLoaderRepository&gt;() &#123;</span><br><span class="line">               @Override</span><br><span class="line">               public ClassLoaderRepository <span class="function"><span class="title">run</span></span>() &#123;</span><br><span class="line">                   <span class="built_in">return</span> fInstantiator.getClassLoaderRepository();</span><br><span class="line">               &#125;</span><br><span class="line">           &#125;)</span><br><span class="line">       );</span><br><span class="line">       <span class="keyword">if</span> (delegate == null)</span><br><span class="line">           delegate = new MBeanServerDelegateImpl();</span><br><span class="line">       <span class="keyword">if</span> (outer == null)</span><br><span class="line">           outer = this;</span><br><span class="line"></span><br><span class="line">       this.instantiator = instantiator;</span><br><span class="line">       this.mBeanServerDelegateObject = delegate;</span><br><span class="line">       this.outerShell   = outer;</span><br><span class="line"></span><br><span class="line">       final Repository repository = new Repository(domain);</span><br><span class="line">       this.mbsInterceptor =</span><br><span class="line">           new DefaultMBeanServerInterceptor(outer, delegate, instantiator,</span><br><span class="line">                                             repository);</span><br><span class="line">       this.interceptorsEnabled = interceptors;</span><br><span class="line">       initialize();</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure></p>
<p>实例化一个Repository并聚合到新生成的一个DefaultMBeanServerInterceptor<br>Repository就是MBeanServer存放MBean的容器类，其内部维护一个Map&lt;String,Map&lt;String,NamedObject&gt;&gt; domainTb的成员<br>此处由于是第一次实例化MBeanServer，传入的domain为null，最终会使用ServiceName的静态的成员值DefaultDomain作为默认域<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">public class ServiceName &#123;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * The default domain.</span><br><span class="line">     * &lt;BR&gt;</span><br><span class="line">     * The value is &lt;CODE&gt;DefaultDomain&lt;/CODE&gt;.</span><br><span class="line">     */</span><br><span class="line">    public static final String DOMAIN = <span class="string">"DefaultDomain"</span>;</span><br><span class="line">	.....</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>NamedObject类是聚合ObjectName和DynamicMBean的辅助类<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">public class NamedObject  &#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * Object name.</span><br><span class="line">     */</span><br><span class="line">    private final ObjectName name;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * Object reference.</span><br><span class="line">     */</span><br><span class="line">    private final DynamicMBean object;</span><br><span class="line">	.....</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>后续的注册bean和获取bean等方法实现最终都是由mbsInterceptor成员去操作</p>
<h3 id="LocateRegistry-createRegistry"><a href="#LocateRegistry-createRegistry" class="headerlink" title="LocateRegistry.createRegistry"></a>LocateRegistry.createRegistry</h3><p>创建注册中心并开启端口监听，返回创建的RegistryImpl实例<br>源码分析请参照本人的另一篇博客——<a href="https://blog.csdn.net/weixin_44627989/article/details/93055791" target="_blank" rel="noopener">java-rmi源码解析</a></p>
<h3 id="MBeanServer-registerMBean"><a href="#MBeanServer-registerMBean" class="headerlink" title="MBeanServer.registerMBean"></a>MBeanServer.registerMBean</h3><p>在JmxMBeanServer中的实现<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">public ObjectInstance registerMBean(Object object, ObjectName name)</span><br><span class="line">       throws InstanceAlreadyExistsException, MBeanRegistrationException,</span><br><span class="line">              NotCompliantMBeanException  &#123;</span><br><span class="line"></span><br><span class="line">       <span class="built_in">return</span> mbsInterceptor.registerMBean(object, cloneObjectName(name));</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure></p>
<p>上面讲到，默认的MBeanServer的mbsInterceptor成员由new DefaultMBeanServerInterceptor(outer, delegate, instantiator,repository)实例化<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line">public ObjectInstance registerMBean(Object object, ObjectName name)</span><br><span class="line">       throws InstanceAlreadyExistsException, MBeanRegistrationException,</span><br><span class="line">       NotCompliantMBeanException  &#123;</span><br><span class="line"></span><br><span class="line">       // ------------------------------</span><br><span class="line">       // ------------------------------</span><br><span class="line">       Class&lt;?&gt; theClass = object.getClass();</span><br><span class="line"></span><br><span class="line">       Introspector.checkCompliance(theClass);</span><br><span class="line"></span><br><span class="line">       final String infoClassName = getNewMBeanClassName(object);</span><br><span class="line"></span><br><span class="line">       checkMBeanPermission(infoClassName, null, name, <span class="string">"registerMBean"</span>);</span><br><span class="line">       checkMBeanTrustPermission(theClass);</span><br><span class="line"></span><br><span class="line">       <span class="built_in">return</span> registerObject(infoClassName, object, name);</span><br><span class="line">   &#125;</span><br><span class="line">private ObjectInstance registerObject(String classname,</span><br><span class="line">                                         Object object, ObjectName name)</span><br><span class="line">       throws InstanceAlreadyExistsException,</span><br><span class="line">              MBeanRegistrationException,</span><br><span class="line">              NotCompliantMBeanException &#123;</span><br><span class="line"></span><br><span class="line">       <span class="keyword">if</span> (object == null) &#123;</span><br><span class="line">           final RuntimeException wrapped =</span><br><span class="line">               new IllegalArgumentException(<span class="string">"Cannot add null object"</span>);</span><br><span class="line">           throw new RuntimeOperationsException(wrapped,</span><br><span class="line">                       <span class="string">"Exception occurred trying to register the MBean"</span>);</span><br><span class="line">       &#125;</span><br><span class="line"></span><br><span class="line">       DynamicMBean mbean = Introspector.makeDynamicMBean(object);</span><br><span class="line"></span><br><span class="line">       <span class="built_in">return</span> registerDynamicMBean(classname, mbean, name);</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure></p>
<p>DefaultMBeanServerInterceptor会将要注册的MBean封装为DynamicMBean，调用registerDynamicMBean进行注册<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br></pre></td><td class="code"><pre><span class="line">private ObjectInstance registerDynamicMBean(String classname,</span><br><span class="line">                                               DynamicMBean mbean,</span><br><span class="line">                                               ObjectName name)</span><br><span class="line">       throws InstanceAlreadyExistsException,</span><br><span class="line">              MBeanRegistrationException,</span><br><span class="line">              NotCompliantMBeanException &#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">       name = nonDefaultDomain(name);</span><br><span class="line"></span><br><span class="line">       <span class="keyword">if</span> (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) &#123;</span><br><span class="line">           MBEANSERVER_LOGGER.logp(Level.FINER,</span><br><span class="line">                   DefaultMBeanServerInterceptor.class.getName(),</span><br><span class="line">                   <span class="string">"registerMBean"</span>, <span class="string">"ObjectName = "</span> + name);</span><br><span class="line">       &#125;</span><br><span class="line"></span><br><span class="line">       ObjectName logicalName = preRegister(mbean, server, name);</span><br><span class="line"></span><br><span class="line">       // preRegister returned successfully, so from this point on we</span><br><span class="line">       // must call postRegister(<span class="literal">false</span>) <span class="keyword">if</span> there is any problem.</span><br><span class="line">       boolean registered = <span class="literal">false</span>;</span><br><span class="line">       boolean registerFailed = <span class="literal">false</span>;</span><br><span class="line">       ResourceContext context = null;</span><br><span class="line"></span><br><span class="line">       try &#123;</span><br><span class="line">           <span class="keyword">if</span> (mbean instanceof DynamicMBean2) &#123;</span><br><span class="line">               try &#123;</span><br><span class="line">                   ((DynamicMBean2) mbean).preRegister2(server, logicalName);</span><br><span class="line">                   registerFailed = <span class="literal">true</span>;  // until we succeed</span><br><span class="line">               &#125; catch (Exception e) &#123;</span><br><span class="line">                   <span class="keyword">if</span> (e instanceof RuntimeException)</span><br><span class="line">                       throw (RuntimeException) e;</span><br><span class="line">                   <span class="keyword">if</span> (e instanceof InstanceAlreadyExistsException)</span><br><span class="line">                       throw (InstanceAlreadyExistsException) e;</span><br><span class="line">                   throw new RuntimeException(e);</span><br><span class="line">               &#125;</span><br><span class="line">           &#125;</span><br><span class="line"></span><br><span class="line">           <span class="keyword">if</span> (logicalName != name &amp;&amp; logicalName != null) &#123;</span><br><span class="line">               logicalName =</span><br><span class="line">                       ObjectName.getInstance(nonDefaultDomain(logicalName));</span><br><span class="line">           &#125;</span><br><span class="line"></span><br><span class="line">           checkMBeanPermission(classname, null, logicalName, <span class="string">"registerMBean"</span>);</span><br><span class="line"></span><br><span class="line">           <span class="keyword">if</span> (logicalName == null) &#123;</span><br><span class="line">               final RuntimeException wrapped =</span><br><span class="line">                   new IllegalArgumentException(<span class="string">"No object name specified"</span>);</span><br><span class="line">               throw new RuntimeOperationsException(wrapped,</span><br><span class="line">                           <span class="string">"Exception occurred trying to register the MBean"</span>);</span><br><span class="line">           &#125;</span><br><span class="line"></span><br><span class="line">           final Object resource = getResource(mbean);</span><br><span class="line"></span><br><span class="line">           // Register the MBean with the repository.</span><br><span class="line">           // Returns the resource context that was used.</span><br><span class="line">           // The returned context does nothing <span class="keyword">for</span> regular MBeans.</span><br><span class="line">           // For ClassLoader MBeans the context makes it possible to register these</span><br><span class="line">           // objects with the appropriate framework artifacts, such as</span><br><span class="line">           // the CLR, from within the repository lock.</span><br><span class="line">           // In <span class="keyword">case</span> of success, we also need to call context.done() at the</span><br><span class="line">           // end of this method.</span><br><span class="line">           //</span><br><span class="line">           context = registerWithRepository(resource, mbean, logicalName);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">           registerFailed = <span class="literal">false</span>;</span><br><span class="line">           registered = <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line">       &#125; finally &#123;</span><br><span class="line">           try &#123;</span><br><span class="line">               postRegister(logicalName, mbean, registered, registerFailed);</span><br><span class="line">           &#125; finally &#123;</span><br><span class="line">               <span class="keyword">if</span> (registered &amp;&amp; context!=null) context.done();</span><br><span class="line">           &#125;</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="built_in">return</span> new ObjectInstance(logicalName, classname);</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure></p>
<p>registerDynamicMBean方法最终调用registerWithRepository方法将DynamicMBean对象注册到Repository里<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">private ResourceContext registerWithRepository(</span><br><span class="line">           final Object resource,</span><br><span class="line">           final DynamicMBean object,</span><br><span class="line">           final ObjectName logicalName)</span><br><span class="line">           throws InstanceAlreadyExistsException,</span><br><span class="line">           MBeanRegistrationException &#123;</span><br><span class="line"></span><br><span class="line">       // Creates a registration context, <span class="keyword">if</span> needed.</span><br><span class="line">       //</span><br><span class="line">       final ResourceContext context =</span><br><span class="line">               makeResourceContextFor(resource, logicalName);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">       repository.addMBean(object, logicalName, context);</span><br><span class="line">       // May throw InstanceAlreadyExistsException</span><br><span class="line"></span><br><span class="line">       // ---------------------</span><br><span class="line">       // Send create event</span><br><span class="line">       // ---------------------</span><br><span class="line">       <span class="keyword">if</span> (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) &#123;</span><br><span class="line">           MBEANSERVER_LOGGER.logp(Level.FINER,</span><br><span class="line">                   DefaultMBeanServerInterceptor.class.getName(),</span><br><span class="line">                   <span class="string">"addObject"</span>, <span class="string">"Send create notification of object "</span> +</span><br><span class="line">                   logicalName.getCanonicalName());</span><br><span class="line">       &#125;</span><br><span class="line"></span><br><span class="line">       sendNotification(</span><br><span class="line">               MBeanServerNotification.REGISTRATION_NOTIFICATION,</span><br><span class="line">               logicalName);</span><br><span class="line"></span><br><span class="line">       <span class="built_in">return</span> context;</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure></p>
<p>前面已经讲过在创建DefaultMBeanServerInterceptor实例时，会实例化一个repository对象并装载到成员<br>注册bean会调用repository的addMBean方法<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br></pre></td><td class="code"><pre><span class="line">public void addMBean(final DynamicMBean object, ObjectName name,</span><br><span class="line">           final RegistrationContext context)</span><br><span class="line">       throws InstanceAlreadyExistsException &#123;</span><br><span class="line"></span><br><span class="line">       <span class="keyword">if</span> (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) &#123;</span><br><span class="line">           MBEANSERVER_LOGGER.logp(Level.FINER, Repository.class.getName(),</span><br><span class="line">                   <span class="string">"addMBean"</span>, <span class="string">"name = "</span> + name);</span><br><span class="line">       &#125;</span><br><span class="line"></span><br><span class="line">       // Extract the domain name.</span><br><span class="line">       String dom = name.getDomain().intern();</span><br><span class="line">       boolean to_default_domain = <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line">       // Set domain to default <span class="keyword">if</span> domain is empty and not already <span class="built_in">set</span></span><br><span class="line">       <span class="keyword">if</span> (dom.length() == 0)</span><br><span class="line">           name = Util.newObjectName(domain + name.toString());</span><br><span class="line"></span><br><span class="line">       // Do we have default domain ?</span><br><span class="line">       <span class="keyword">if</span> (dom == domain) &#123;  // ES: OK (dom &amp; domain are interned)</span><br><span class="line">           to_default_domain = <span class="literal">true</span>;</span><br><span class="line">           dom = domain;</span><br><span class="line">       &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">           to_default_domain = <span class="literal">false</span>;</span><br><span class="line">       &#125;</span><br><span class="line"></span><br><span class="line">       // Validate name <span class="keyword">for</span> an object</span><br><span class="line">       <span class="keyword">if</span> (name.isPattern()) &#123;</span><br><span class="line">           throw new RuntimeOperationsException(</span><br><span class="line">            new IllegalArgumentException(<span class="string">"Repository: cannot add mbean for "</span> +</span><br><span class="line">                                         <span class="string">"pattern name "</span> + name.toString()));</span><br><span class="line">       &#125;</span><br><span class="line"></span><br><span class="line">       lock.writeLock().lock();</span><br><span class="line">       try &#123;</span><br><span class="line">           // Domain cannot be JMImplementation <span class="keyword">if</span> entry does not exist</span><br><span class="line">           <span class="keyword">if</span> ( !to_default_domain &amp;&amp;</span><br><span class="line">                   dom.equals(<span class="string">"JMImplementation"</span>) &amp;&amp;</span><br><span class="line">                   domainTb.containsKey(<span class="string">"JMImplementation"</span>)) &#123;</span><br><span class="line">               throw new RuntimeOperationsException(</span><br><span class="line">                       new IllegalArgumentException(</span><br><span class="line">                       <span class="string">"Repository: domain name cannot be JMImplementation"</span>));</span><br><span class="line">           &#125;</span><br><span class="line"></span><br><span class="line">           // If domain does not already exist, add it to the <span class="built_in">hash</span> table</span><br><span class="line">           final Map&lt;String,NamedObject&gt; moiTb = domainTb.get(dom);</span><br><span class="line">           <span class="keyword">if</span> (moiTb == null) &#123;</span><br><span class="line">               addNewDomMoi(object, dom, name, context);</span><br><span class="line">               <span class="built_in">return</span>;</span><br><span class="line">           &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">               // Add instance <span class="keyword">if</span> not already present</span><br><span class="line">               String cstr = name.getCanonicalKeyPropertyListString();</span><br><span class="line">               NamedObject elmt= moiTb.get(cstr);</span><br><span class="line">               <span class="keyword">if</span> (elmt != null) &#123;</span><br><span class="line">                   throw new InstanceAlreadyExistsException(name.toString());</span><br><span class="line">               &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                   nbElements++;</span><br><span class="line">                   addMoiToTb(object,name,cstr,moiTb,context);</span><br><span class="line">               &#125;</span><br><span class="line">           &#125;</span><br><span class="line"></span><br><span class="line">       &#125; finally &#123;</span><br><span class="line">           lock.writeLock().unlock();</span><br><span class="line">       &#125;</span><br><span class="line">   &#125;</span><br><span class="line">private void addMoiToTb(final DynamicMBean object,</span><br><span class="line">           final ObjectName name,</span><br><span class="line">           final String key,</span><br><span class="line">           final Map&lt;String,NamedObject&gt; moiTb,</span><br><span class="line">           final RegistrationContext context) &#123;</span><br><span class="line">       registering(context);</span><br><span class="line">       moiTb.put(key,new NamedObject(name, object));</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure></p>
<p>domainTb成员就是前面说过的repository中存储MBean的Map，类型是Map&lt;String,Map&lt;String,NamedObject&gt;&gt;<br>add方法里会通过writelock进行同步<br>如果获取到的moiTb，代表该MBean的域名尚未加入domainTb，会将域名加入map并将MBean也加入</p>
<h2 id="JmxMBeanServer"><a href="#JmxMBeanServer" class="headerlink" title="JmxMBeanServer"></a>JmxMBeanServer</h2><p>JmxMBeanServer<br>不提供直接返回MBean对象的方法<br>但提供了很多行为如 setAttributes，getAttribute，invoke等方法，根据ObjectName参数进行MBean识别<br>调用成员的DefaultMBeanServerInterceptor实例去执行对应的修改属性，获取属性值，执行方法等行为<br>DefaultMBeanServerInterceptor最终是获取repository中的MBean去执行对应行为<br>通过getObjectInstance可以获得该MBean的类名和域名信息的封装对象<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">public ObjectInstance getObjectInstance(ObjectName name)</span><br><span class="line">       throws InstanceNotFoundException &#123;</span><br><span class="line"></span><br><span class="line">       <span class="built_in">return</span> mbsInterceptor.getObjectInstance(cloneObjectName(name));</span><br><span class="line">   &#125;</span><br><span class="line">public Object getAttribute(ObjectName name, String attribute)</span><br><span class="line">       throws MBeanException, AttributeNotFoundException,</span><br><span class="line">              InstanceNotFoundException, ReflectionException &#123;</span><br><span class="line"></span><br><span class="line">       <span class="built_in">return</span> mbsInterceptor.getAttribute(cloneObjectName(name), attribute);</span><br><span class="line">   &#125;</span><br><span class="line">public void setAttribute(ObjectName name, Attribute attribute)</span><br><span class="line">       throws InstanceNotFoundException, AttributeNotFoundException,</span><br><span class="line">              InvalidAttributeValueException, MBeanException,</span><br><span class="line">              ReflectionException  &#123;</span><br><span class="line"></span><br><span class="line">       mbsInterceptor.setAttribute(cloneObjectName(name),</span><br><span class="line">                                   cloneAttribute(attribute));</span><br><span class="line">   &#125;</span><br><span class="line">public Object invoke(ObjectName name, String operationName,</span><br><span class="line">                        Object params[], String signature[])</span><br><span class="line">       throws InstanceNotFoundException, MBeanException,</span><br><span class="line">              ReflectionException &#123;</span><br><span class="line">       <span class="built_in">return</span> mbsInterceptor.invoke(cloneObjectName(name), operationName,</span><br><span class="line">                                    params, signature);</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="JMXConnectorServerFactory-newJMXConnectorServer"><a href="#JMXConnectorServerFactory-newJMXConnectorServer" class="headerlink" title="JMXConnectorServerFactory.newJMXConnectorServer"></a>JMXConnectorServerFactory.newJMXConnectorServer</h2><p>该方法创建一个JMXConnectorServer，将MBeanServer和JMXServiceURL传递过去<br>最终url、MbeanServer等对象会被聚合到JMXConnectorServer，作为成员<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br></pre></td><td class="code"><pre><span class="line">public static JMXConnectorServer</span><br><span class="line">    newJMXConnectorServer(JMXServiceURL serviceURL,</span><br><span class="line">                          Map&lt;String,?&gt; environment,</span><br><span class="line">                          MBeanServer mbeanServer)</span><br><span class="line">        throws IOException &#123;</span><br><span class="line">    Map&lt;String, Object&gt; envcopy;</span><br><span class="line">    <span class="keyword">if</span> (environment == null)</span><br><span class="line">        envcopy = new HashMap&lt;String, Object&gt;();</span><br><span class="line">    <span class="keyword">else</span> &#123;</span><br><span class="line">        EnvHelp.checkAttributes(environment);</span><br><span class="line">        envcopy = new HashMap&lt;String, Object&gt;(environment);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    final Class&lt;JMXConnectorServerProvider&gt; targetInterface =</span><br><span class="line">            JMXConnectorServerProvider.class;</span><br><span class="line">    final ClassLoader loader =</span><br><span class="line">        JMXConnectorFactory.resolveClassLoader(envcopy);</span><br><span class="line">    final String protocol = serviceURL.getProtocol();</span><br><span class="line">    final String providerClassName = <span class="string">"ServerProvider"</span>;</span><br><span class="line"></span><br><span class="line">    JMXConnectorServerProvider provider =</span><br><span class="line">        JMXConnectorFactory.getProvider(serviceURL,</span><br><span class="line">                                        envcopy,</span><br><span class="line">                                        providerClassName,</span><br><span class="line">                                        targetInterface,</span><br><span class="line">                                        loader);</span><br><span class="line"></span><br><span class="line">    IOException exception = null;</span><br><span class="line">    <span class="keyword">if</span> (provider == null) &#123;</span><br><span class="line">        // Loader is null when context class loader is <span class="built_in">set</span> to null</span><br><span class="line">        // and no loader has been provided <span class="keyword">in</span> map.</span><br><span class="line">        // com.sun.jmx.remote.util.Service class extracted from j2se</span><br><span class="line">        // provider search algorithm doesn<span class="string">'t handle well null classloader.</span></span><br><span class="line"><span class="string">        if (loader != null) &#123;</span></span><br><span class="line"><span class="string">            try &#123;</span></span><br><span class="line"><span class="string">                JMXConnectorServer connection =</span></span><br><span class="line"><span class="string">                    getConnectorServerAsService(loader,</span></span><br><span class="line"><span class="string">                                                serviceURL,</span></span><br><span class="line"><span class="string">                                                envcopy,</span></span><br><span class="line"><span class="string">                                                mbeanServer);</span></span><br><span class="line"><span class="string">                if (connection != null)</span></span><br><span class="line"><span class="string">                    return connection;</span></span><br><span class="line"><span class="string">            &#125; catch (JMXProviderException e) &#123;</span></span><br><span class="line"><span class="string">                throw e;</span></span><br><span class="line"><span class="string">            &#125; catch (IOException e) &#123;</span></span><br><span class="line"><span class="string">                exception = e;</span></span><br><span class="line"><span class="string">            &#125;</span></span><br><span class="line"><span class="string">        &#125;</span></span><br><span class="line"><span class="string">        provider =</span></span><br><span class="line"><span class="string">            JMXConnectorFactory.getProvider(</span></span><br><span class="line"><span class="string">                protocol,</span></span><br><span class="line"><span class="string">                PROTOCOL_PROVIDER_DEFAULT_PACKAGE,</span></span><br><span class="line"><span class="string">                JMXConnectorFactory.class.getClassLoader(),</span></span><br><span class="line"><span class="string">                providerClassName,</span></span><br><span class="line"><span class="string">                targetInterface);</span></span><br><span class="line"><span class="string">    &#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    if (provider == null) &#123;</span></span><br><span class="line"><span class="string">        MalformedURLException e =</span></span><br><span class="line"><span class="string">            new MalformedURLException("Unsupported protocol: " + protocol);</span></span><br><span class="line"><span class="string">        if (exception == null) &#123;</span></span><br><span class="line"><span class="string">            throw e;</span></span><br><span class="line"><span class="string">        &#125; else &#123;</span></span><br><span class="line"><span class="string">            throw EnvHelp.initCause(e, exception);</span></span><br><span class="line"><span class="string">        &#125;</span></span><br><span class="line"><span class="string">    &#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    envcopy = Collections.unmodifiableMap(envcopy);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    return provider.newJMXConnectorServer(serviceURL,</span></span><br><span class="line"><span class="string">                                          envcopy,</span></span><br><span class="line"><span class="string">                                          mbeanServer);</span></span><br><span class="line"><span class="string">&#125;</span></span><br></pre></td></tr></table></figure></p>
<p>JMXConnectorServerFactory的newJMXConnectorServer最终是返回由provider生产的JMXConnectorServer<br>provider是接口，在jdk里对于该方法有两个实现类，一个是返回基于rmi协议，另一个是返回基于iiop协议的<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">//ServiceProvider <span class="keyword">for</span> rmi</span><br><span class="line">public JMXConnectorServer newJMXConnectorServer(JMXServiceURL serviceURL,</span><br><span class="line">                                                   Map&lt;String,?&gt; environment,</span><br><span class="line">                                                   MBeanServer mbeanServer)</span><br><span class="line">           throws IOException &#123;</span><br><span class="line">       <span class="keyword">if</span> (!serviceURL.getProtocol().equals(<span class="string">"rmi"</span>)) &#123;</span><br><span class="line">           throw new MalformedURLException(<span class="string">"Protocol not rmi: "</span> +</span><br><span class="line">                                           serviceURL.getProtocol());</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="built_in">return</span> new RMIConnectorServer(serviceURL, environment, mbeanServer);</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure></p>
<p>需要留意的是，在serviceProvider中调用生成RMIConnectorServer时，最终会调用传递(RMIServerImpl) null为形参参数的构造函数构造<br>也就是生成的RMIConnectorServer中是没有指定服务端对象的<br>RMIServerImpl会在JMXConnectorServer调用start方法后结合前面聚合到JMXConnectorServer中的rmi的url去实例化<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line">   public RMIConnectorServer(JMXServiceURL url, Map&lt;String,?&gt; environment,</span><br><span class="line">                             MBeanServer mbeanServer)</span><br><span class="line">           throws IOException &#123;</span><br><span class="line">       this(url, environment, (RMIServerImpl) null, mbeanServer);</span><br><span class="line">   &#125;</span><br><span class="line">public RMIConnectorServer(JMXServiceURL url, Map&lt;String,?&gt; environment,</span><br><span class="line">                             RMIServerImpl rmiServerImpl,</span><br><span class="line">                             MBeanServer mbeanServer)</span><br><span class="line">           throws IOException &#123;</span><br><span class="line">       super(mbeanServer);</span><br><span class="line"></span><br><span class="line">       <span class="keyword">if</span> (url == null) throw new</span><br><span class="line">           IllegalArgumentException(<span class="string">"Null JMXServiceURL"</span>);</span><br><span class="line">       <span class="keyword">if</span> (rmiServerImpl == null) &#123;</span><br><span class="line">           final String prt = url.getProtocol();</span><br><span class="line">           <span class="keyword">if</span> (prt == null || !(prt.equals(<span class="string">"rmi"</span>) || prt.equals(<span class="string">"iiop"</span>))) &#123;</span><br><span class="line">               final String msg = <span class="string">"Invalid protocol type: "</span> + prt;</span><br><span class="line">               throw new MalformedURLException(msg);</span><br><span class="line">           &#125;</span><br><span class="line">           final String urlPath = url.getURLPath();</span><br><span class="line">           <span class="keyword">if</span> (!urlPath.equals(<span class="string">""</span>)</span><br><span class="line">               &amp;&amp; !urlPath.equals(<span class="string">"/"</span>)</span><br><span class="line">               &amp;&amp; !urlPath.startsWith(<span class="string">"/jndi/"</span>)) &#123;</span><br><span class="line">               final String msg = <span class="string">"URL path must be empty or start with "</span> +</span><br><span class="line">                   <span class="string">"/jndi/"</span>;</span><br><span class="line">               throw new MalformedURLException(msg);</span><br><span class="line">           &#125;</span><br><span class="line">       &#125;</span><br><span class="line"></span><br><span class="line">       <span class="keyword">if</span> (environment == null)</span><br><span class="line">           this.attributes = Collections.emptyMap();</span><br><span class="line">       <span class="keyword">else</span> &#123;</span><br><span class="line">           EnvHelp.checkAttributes(environment);</span><br><span class="line">           this.attributes = Collections.unmodifiableMap(environment);</span><br><span class="line">       &#125;</span><br><span class="line"></span><br><span class="line">       this.address = url;</span><br><span class="line">       this.rmiServerImpl = rmiServerImpl;</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="jmxConnectorServer-start"><a href="#jmxConnectorServer-start" class="headerlink" title="jmxConnectorServer.start()"></a>jmxConnectorServer.start()</h2><p>启动JMX链接服务器，该过程会完成rmiServerImpl的实例化（开启监听rmi服务端口）<br>所以如果前面没有调用LocateRegistry.createRegistry(rmiPort)对端口进行注册，会导致报错<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br></pre></td><td class="code"><pre><span class="line">public synchronized void start() throws IOException &#123;</span><br><span class="line">        final boolean tracing = logger.traceOn();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (state == STARTED) &#123;</span><br><span class="line">            <span class="keyword">if</span> (tracing) logger.trace(<span class="string">"start"</span>, <span class="string">"already started"</span>);</span><br><span class="line">            <span class="built_in">return</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (state == STOPPED) &#123;</span><br><span class="line">            <span class="keyword">if</span> (tracing) logger.trace(<span class="string">"start"</span>, <span class="string">"already stopped"</span>);</span><br><span class="line">            throw new IOException(<span class="string">"The server has been stopped."</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (getMBeanServer() == null)</span><br><span class="line">            throw new IllegalStateException(<span class="string">"This connector server is not "</span> +</span><br><span class="line">                                            <span class="string">"attached to an MBean server"</span>);</span><br><span class="line"></span><br><span class="line">        // Check the internal access file property to see</span><br><span class="line">        // <span class="keyword">if</span> an MBeanServerForwarder is to be provided</span><br><span class="line">        //</span><br><span class="line">        <span class="keyword">if</span> (attributes != null) &#123;</span><br><span class="line">            // Check <span class="keyword">if</span> access file property is specified</span><br><span class="line">            //</span><br><span class="line">            String accessFile =</span><br><span class="line">                (String) attributes.get(<span class="string">"jmx.remote.x.access.file"</span>);</span><br><span class="line">            <span class="keyword">if</span> (accessFile != null) &#123;</span><br><span class="line">                // Access file property specified, create an instance</span><br><span class="line">                // of the MBeanServerFileAccessController class</span><br><span class="line">                //</span><br><span class="line">                MBeanServerForwarder mbsf;</span><br><span class="line">                try &#123;</span><br><span class="line">                    mbsf = new MBeanServerFileAccessController(accessFile);</span><br><span class="line">                &#125; catch (IOException e) &#123;</span><br><span class="line">                    throw EnvHelp.initCause(</span><br><span class="line">                        new IllegalArgumentException(e.getMessage()), e);</span><br><span class="line">                &#125;</span><br><span class="line">                // Set the MBeanServerForwarder</span><br><span class="line">                //</span><br><span class="line">                setMBeanServerForwarder(mbsf);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        try &#123;</span><br><span class="line">            <span class="keyword">if</span> (tracing) logger.trace(<span class="string">"start"</span>, <span class="string">"setting default class loader"</span>);</span><br><span class="line">            defaultClassLoader = EnvHelp.resolveServerClassLoader(</span><br><span class="line">                    attributes, getMBeanServer());</span><br><span class="line">        &#125; catch (InstanceNotFoundException infc) &#123;</span><br><span class="line">            IllegalArgumentException x = new</span><br><span class="line">                IllegalArgumentException(<span class="string">"ClassLoader not found: "</span>+infc);</span><br><span class="line">            throw EnvHelp.initCause(x,infc);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (tracing) logger.trace(<span class="string">"start"</span>, <span class="string">"setting RMIServer object"</span>);</span><br><span class="line">        final RMIServerImpl rmiServer;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (rmiServerImpl != null)</span><br><span class="line">            rmiServer = rmiServerImpl;</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">            rmiServer = newServer();</span><br><span class="line"></span><br><span class="line">        rmiServer.setMBeanServer(getMBeanServer());</span><br><span class="line">        rmiServer.setDefaultClassLoader(defaultClassLoader);</span><br><span class="line">        rmiServer.setRMIConnectorServer(this);</span><br><span class="line">        rmiServer.export();</span><br><span class="line"></span><br><span class="line">        try &#123;</span><br><span class="line">            <span class="keyword">if</span> (tracing) logger.trace(<span class="string">"start"</span>, <span class="string">"getting RMIServer object to export"</span>);</span><br><span class="line">            final RMIServer objref = objectToBind(rmiServer, attributes);</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (address != null &amp;&amp; address.getURLPath().startsWith(<span class="string">"/jndi/"</span>)) &#123;</span><br><span class="line">                final String jndiUrl = address.getURLPath().substring(6);</span><br><span class="line"></span><br><span class="line">                <span class="keyword">if</span> (tracing)</span><br><span class="line">                    logger.trace(<span class="string">"start"</span>, <span class="string">"Using external directory: "</span> + jndiUrl);</span><br><span class="line"></span><br><span class="line">                String stringBoolean = (String) attributes.get(JNDI_REBIND_ATTRIBUTE);</span><br><span class="line">                final boolean rebind = EnvHelp.computeBooleanFromString( stringBoolean );</span><br><span class="line"></span><br><span class="line">                <span class="keyword">if</span> (tracing)</span><br><span class="line">                    logger.trace(<span class="string">"start"</span>, JNDI_REBIND_ATTRIBUTE + <span class="string">"="</span> + rebind);</span><br><span class="line"></span><br><span class="line">                try &#123;</span><br><span class="line">                    <span class="keyword">if</span> (tracing) logger.trace(<span class="string">"start"</span>, <span class="string">"binding to "</span> + jndiUrl);</span><br><span class="line"></span><br><span class="line">                    final Hashtable&lt;?, ?&gt; usemap = EnvHelp.mapToHashtable(attributes);</span><br><span class="line"></span><br><span class="line">                    <span class="built_in">bind</span>(jndiUrl, usemap, objref, rebind);</span><br><span class="line"></span><br><span class="line">                    boundJndiUrl = jndiUrl;</span><br><span class="line">                &#125; catch (NamingException e) &#123;</span><br><span class="line">                    // fit e <span class="keyword">in</span> the nested exception <span class="keyword">if</span> we are on 1.4</span><br><span class="line">                    throw newIOException(<span class="string">"Cannot bind to URL ["</span>+jndiUrl+<span class="string">"]: "</span></span><br><span class="line">                                         + e, e);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                // <span class="keyword">if</span> jndiURL is null, we must encode the stub into the URL.</span><br><span class="line">                <span class="keyword">if</span> (tracing) logger.trace(<span class="string">"start"</span>, <span class="string">"Encoding URL"</span>);</span><br><span class="line"></span><br><span class="line">                encodeStubInAddress(objref, attributes);</span><br><span class="line"></span><br><span class="line">                <span class="keyword">if</span> (tracing) logger.trace(<span class="string">"start"</span>, <span class="string">"Encoded URL: "</span> + this.address);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; catch (Exception e) &#123;</span><br><span class="line">            try &#123;</span><br><span class="line">                rmiServer.close();</span><br><span class="line">            &#125; catch (Exception x) &#123;</span><br><span class="line">                // OK: we are already throwing another exception</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (e instanceof RuntimeException)</span><br><span class="line">                throw (RuntimeException) e;</span><br><span class="line">            <span class="keyword">else</span> <span class="keyword">if</span> (e instanceof IOException)</span><br><span class="line">                throw (IOException) e;</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">                throw newIOException(<span class="string">"Got unexpected exception while "</span> +</span><br><span class="line">                                     <span class="string">"starting the connector server: "</span></span><br><span class="line">                                     + e, e);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        rmiServerImpl = rmiServer;</span><br><span class="line"></span><br><span class="line">        synchronized(openedServers) &#123;</span><br><span class="line">            openedServers.add(this);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        state = STARTED;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (tracing) &#123;</span><br><span class="line">            logger.trace(<span class="string">"start"</span>, <span class="string">"Connector Server Address = "</span> + address);</span><br><span class="line">            logger.trace(<span class="string">"start"</span>, <span class="string">"started."</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure></p>
<p>前面讲过rmiServerImpl成员是空的，所以这时会调用newServer方法进行创建<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">RMIServerImpl newServer() throws IOException &#123;</span><br><span class="line">    final boolean iiop = isIiopURL(address,<span class="literal">true</span>);</span><br><span class="line">    final int port;</span><br><span class="line">    <span class="keyword">if</span> (address == null)</span><br><span class="line">        port = 0;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">        port = address.getPort();</span><br><span class="line">    <span class="keyword">if</span> (iiop)</span><br><span class="line">        <span class="built_in">return</span> newIIOPServer(attributes);</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">        <span class="built_in">return</span> newJRMPServer(attributes, port);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>接下来会调用objectToBind<br>通过toStub方法创建当前的RMIServer对象的远程代理对象<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">private static RMIServer objectToBind(</span><br><span class="line">           RMIServerImpl rmiServer, Map&lt;String, ?&gt; env)</span><br><span class="line">       throws IOException &#123;</span><br><span class="line">       <span class="built_in">return</span> RMIConnector.</span><br><span class="line">           connectStub((RMIServer)rmiServer.toStub(),env);</span><br><span class="line">   &#125;</span><br><span class="line">public Remote toStub() throws IOException &#123;</span><br><span class="line">       <span class="built_in">return</span> RemoteObject.toStub(this);</span><br><span class="line">   &#125;</span><br><span class="line">public static Remote toStub(Remote obj) throws NoSuchObjectException &#123;</span><br><span class="line">       <span class="keyword">if</span> (obj instanceof RemoteStub ||</span><br><span class="line">           (obj != null &amp;&amp;</span><br><span class="line">            Proxy.isProxyClass(obj.getClass()) &amp;&amp;</span><br><span class="line">            Proxy.getInvocationHandler(obj) instanceof</span><br><span class="line">            RemoteObjectInvocationHandler))</span><br><span class="line">       &#123;</span><br><span class="line">           <span class="built_in">return</span> obj;</span><br><span class="line">       &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">           <span class="built_in">return</span> sun.rmi.transport.ObjectTable.getStub(obj);</span><br><span class="line">       &#125;</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure></p>
<p>然后调用bind方法将RMIServer的远程代理对象注册到注册中心<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">void <span class="built_in">bind</span>(String jndiUrl, Hashtable&lt;?, ?&gt; attributes,</span><br><span class="line">             RMIServer rmiServer, boolean rebind)</span><br><span class="line">       throws NamingException, MalformedURLException &#123;</span><br><span class="line">       // <span class="keyword">if</span> jndiURL is not null, we nust <span class="built_in">bind</span> the stub to a</span><br><span class="line">       // directory.</span><br><span class="line">       InitialContext ctx =</span><br><span class="line">           new InitialContext(attributes);</span><br><span class="line"></span><br><span class="line">       <span class="keyword">if</span> (rebind)</span><br><span class="line">           ctx.rebind(jndiUrl, rmiServer);</span><br><span class="line">       <span class="keyword">else</span></span><br><span class="line">           ctx.bind(jndiUrl, rmiServer);</span><br><span class="line">       ctx.close();</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure></p>
<p>至此，完成了JmxConnectorServer的启动，程序可以通过jmx规范，访问MBeanServer与其上的MBean<br>关于remote和rmi的细节可以参考本人另一篇博客——java-rmi源码解析<a href="https://blog.csdn.net/weixin_44627989/article/details/93055791" target="_blank" rel="noopener">java-rmi源码解析</a></p>
<h3 id="更多精彩内容"><a href="#更多精彩内容" class="headerlink" title="更多精彩内容"></a>更多精彩内容</h3><h3 id="请移步"><a href="#请移步" class="headerlink" title="请移步"></a>请移步</h3><p>个人主页: <a href="http://yangyitao.top" target="_blank" rel="noopener">yangyitao.top</a></p>

      
    </div>
    
  </div>
  
    
<nav id="article-nav">
  
    <a href="/blog/2019/07/11/zookeeper集群搭建/" id="article-nav-newer" class="article-nav-link-wrap">
      <strong class="article-nav-caption">&lt;</strong>
      <div class="article-nav-title">
        
          zookeeper集群搭建
        
      </div>
    </a>
  
  
    <a href="/blog/2019/06/20/java-rmi源码解析/" id="article-nav-older" class="article-nav-link-wrap">
      <div class="article-nav-title">java-rmi源码解析</div>
      <strong class="article-nav-caption">&gt;</strong>
    </a>
  
</nav>

  
</article>


<div class="ds-share share" data-thread-key="MBean与JMX" data-title="MBean与JMX" data-url="http://eetal.gitee.io/blog/blog/2019/07/08/MBean与JMX/"  data-images="/blog/images/head.jpg" data-content="MBean与JMX">
    <div class="ds-share-inline">
      <ul  class="ds-share-icons-16">
      	<li data-toggle="ds-share-icons-more"><a class="ds-more" href="javascript:void(0);">分享到：</a></li>
        <li><a class="ds-weibo" href="javascript:void(0);" data-service="weibo">微博</a></li>
        <li><a class="ds-qzone" href="javascript:void(0);" data-service="qzone">QQ空间</a></li>
        <li><a class="ds-qqt" href="javascript:void(0);" data-service="qqt">腾讯微博</a></li>
        <li><a class="ds-wechat" href="javascript:void(0);" data-service="wechat">微信</a></li>
      </ul>
      <div class="ds-share-icons-more">
      </div>
    </div>
 </div>
 





</div>
      <footer id="footer">
  <div class="outer">
    <div id="footer-info">
      <div class="footer-left">
        &copy; 2019 Eetal
      </div>
        <div class="footer-right">
          <a href="http://hexo.io/" target="_blank">Hexo</a>  Theme <a href="https://github.com/smackgg/hexo-theme-smackdown" target="_blank">Smackdown</a>
        </div>
    </div>
  </div>
</footer>
    </div>
    
  <link rel="stylesheet" href="/blog/fancybox/jquery.fancybox.css">


<script>
	var yiliaConfig = {
		fancybox: true,
		mathjax: true,
		animate: true,
		isHome: false,
		isPost: true,
		isArchive: false,
		isTag: false,
		isCategory: false,
		open_in_new: false
	}
</script>
<script src="/blog/js/main.js"></script>



<script type="text/x-mathjax-config">
MathJax.Hub.Config({
    tex2jax: {
        inlineMath: [ ['$','$'], ["\\(","\\)"]  ],
        processEscapes: true,
        skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
    }
});

MathJax.Hub.Queue(function() {
    var all = MathJax.Hub.getAllJax(), i;
    for(i=0; i < all.length; i += 1) {
        all[i].SourceElement().parentNode.className += ' has-jax';                 
    }       
});
</script>

<script src="//cdn.bootcss.com/mathjax/2.7.0/MathJax.js"></script>


  </div>
</body>
</html>